/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

var echarts = require("../../echarts");

var List = require("../../data/List");

var zrUtil = require("static/plugins/js/zrender/lib/core/util");

var _model = require("../../util/model");

var defaultEmphasis = _model.defaultEmphasis;

var Model = require("../../model/Model");

var _format = require("../../util/format");

var encodeHTML = _format.encodeHTML;

var createGraphFromNodeEdge = require("../helper/createGraphFromNodeEdge");

var LegendVisualProvider = require("../../visual/LegendVisualProvider");

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
var GraphSeries = echarts.extendSeriesModel({
    type: "series.graph",
    init: function (option) {
        GraphSeries.superApply(this, "init", arguments);
        var self = this;

        function getCategoriesData() {
            return self._categoriesData;
        } // Provide data for legend select

        this.legendVisualProvider = new LegendVisualProvider(
            getCategoriesData,
            getCategoriesData
        );
        this.fillDataTextStyle(option.edges || option.links);

        this._updateCategoriesData();
    },
    mergeOption: function (option) {
        GraphSeries.superApply(this, "mergeOption", arguments);
        this.fillDataTextStyle(option.edges || option.links);

        this._updateCategoriesData();
    },
    mergeDefaultAndTheme: function (option) {
        GraphSeries.superApply(this, "mergeDefaultAndTheme", arguments);
        defaultEmphasis(option, ["edgeLabel"], ["show"]);
    },
    getInitialData: function (option, ecModel) {
        var edges = option.edges || option.links || [];
        var nodes = option.data || option.nodes || [];
        var self = this;

        if (nodes && edges) {
            return createGraphFromNodeEdge(nodes, edges, this, true, beforeLink)
                .data;
        }

        function beforeLink(nodeData, edgeData) {
            // Overwrite nodeData.getItemModel to
            nodeData.wrapMethod("getItemModel", function (model) {
                var categoriesModels = self._categoriesModels;
                var categoryIdx = model.getShallow("category");
                var categoryModel = categoriesModels[categoryIdx];

                if (categoryModel) {
                    categoryModel.parentModel = model.parentModel;
                    model.parentModel = categoryModel;
                }

                return model;
            });
            var edgeLabelModel = self.getModel("edgeLabel"); // For option `edgeLabel` can be found by label.xxx.xxx on item mode.

            var fakeSeriesModel = new Model(
                {
                    label: edgeLabelModel.option,
                },
                edgeLabelModel.parentModel,
                ecModel
            );
            var emphasisEdgeLabelModel = self.getModel("emphasis.edgeLabel");
            var emphasisFakeSeriesModel = new Model(
                {
                    emphasis: {
                        label: emphasisEdgeLabelModel.option,
                    },
                },
                emphasisEdgeLabelModel.parentModel,
                ecModel
            );
            edgeData.wrapMethod("getItemModel", function (model) {
                model.customizeGetParent(edgeGetParent);
                return model;
            });

            function edgeGetParent(path) {
                path = this.parsePath(path);
                return path && path[0] === "label"
                    ? fakeSeriesModel
                    : path && path[0] === "emphasis" && path[1] === "label"
                    ? emphasisFakeSeriesModel
                    : this.parentModel;
            }
        }
    },

    /**
     * @return {module:echarts/data/Graph}
     */
    getGraph: function () {
        return this.getData().graph;
    },

    /**
     * @return {module:echarts/data/List}
     */
    getEdgeData: function () {
        return this.getGraph().edgeData;
    },

    /**
     * @return {module:echarts/data/List}
     */
    getCategoriesData: function () {
        return this._categoriesData;
    },

    /**
     * @override
     */
    formatTooltip: function (dataIndex, multipleSeries, dataType) {
        if (dataType === "edge") {
            var nodeData = this.getData();
            var params = this.getDataParams(dataIndex, dataType);
            var edge = nodeData.graph.getEdgeByIndex(dataIndex);
            var sourceName = nodeData.getName(edge.node1.dataIndex);
            var targetName = nodeData.getName(edge.node2.dataIndex);
            var html = [];
            sourceName != null && html.push(sourceName);
            targetName != null && html.push(targetName);
            html = encodeHTML(html.join(" > "));

            if (params.value) {
                html += " : " + encodeHTML(params.value);
            }

            return html;
        } else {
            // dataType === 'node' or empty
            return GraphSeries.superApply(this, "formatTooltip", arguments);
        }
    },
    _updateCategoriesData: function () {
        var categories = zrUtil.map(
            this.option.categories || [],
            function (category) {
                // Data must has value
                return category.value != null
                    ? category
                    : zrUtil.extend(
                          {
                              value: 0,
                          },
                          category
                      );
            }
        );
        var categoriesData = new List(["value"], this);
        categoriesData.initData(categories);
        this._categoriesData = categoriesData;
        this._categoriesModels = categoriesData.mapArray(function (idx) {
            return categoriesData.getItemModel(idx, true);
        });
    },
    setZoom: function (zoom) {
        this.option.zoom = zoom;
    },
    setCenter: function (center) {
        this.option.center = center;
    },
    isAnimationEnabled: function () {
        return (
            GraphSeries.superCall(this, "isAnimationEnabled") && // Not enable animation when do force layout
            !(
                this.get("layout") === "force" &&
                this.get("force.layoutAnimation")
            )
        );
    },
    defaultOption: {
        zlevel: 0,
        z: 2,
        coordinateSystem: "view",
        // Default option for all coordinate systems
        // xAxisIndex: 0,
        // yAxisIndex: 0,
        // polarIndex: 0,
        // geoIndex: 0,
        legendHoverLink: true,
        hoverAnimation: true,
        layout: null,
        focusNodeAdjacency: false,
        // Configuration of circular layout
        circular: {
            rotateLabel: false,
        },
        // Configuration of force directed layout
        force: {
            initLayout: null,
            // Node repulsion. Can be an array to represent range.
            repulsion: [0, 50],
            gravity: 0.1,
            // Initial friction
            friction: 0.6,
            // Edge length. Can be an array to represent range.
            edgeLength: 30,
            layoutAnimation: true,
        },
        left: "center",
        top: "center",
        // right: null,
        // bottom: null,
        // width: '80%',
        // height: '80%',
        symbol: "circle",
        symbolSize: 10,
        edgeSymbol: ["none", "none"],
        edgeSymbolSize: 10,
        edgeLabel: {
            position: "middle",
            distance: 5,
        },
        draggable: false,
        roam: false,
        // Default on center of graph
        center: null,
        zoom: 1,
        // Symbol size scale ratio in roam
        nodeScaleRatio: 0.6,
        // cursor: null,
        // categories: [],
        // data: []
        // Or
        // nodes: []
        //
        // links: []
        // Or
        // edges: []
        label: {
            show: false,
            formatter: "{b}",
        },
        itemStyle: {},
        lineStyle: {
            color: "#aaa",
            width: 1,
            curveness: 0,
            opacity: 0.5,
        },
        emphasis: {
            label: {
                show: true,
            },
        },
    },
});
var _default = GraphSeries;
module.exports = _default;
